# coding=utf-8
"""
logger class
Author: kaspar
Date: 2022-03-31
"""
import logging
import os
import time
import threading
import datetime
# import fcntl
import traceback
from logging.handlers import TimedRotatingFileHandler

lock = threading.RLock()
# Override TimedRotatingFileHandler for multipressing
class MutilRotatingFileHandler(TimedRotatingFileHandler):
    """
    Override TimedRotatingFileHandler class
    """

    def __init__(self, filename, when='h', interval=1, backupCount=0, \
                 encoding=None, delay=False, utc=False):
        """
        init func
        """
        TimedRotatingFileHandler.__init__(self, filename, when, interval, \
                                          backupCount, encoding, delay, utc)

    def doRollover(self):
        """
        Override doRollover
        """
        if self.stream:
            self.stream.close()
            self.stream = None
        currentTime = int(time.time())
        dstNow = time.localtime(currentTime)[-1]
        t = self.rolloverAt - self.interval
        if self.utc:
            timeTuple = time.gmtime(t)
        else:
            timeTuple = time.localtime(t)
            dstThen = timeTuple[-1]
            if dstNow != dstThen:
                if dstNow:
                    addend = 3600
                else:
                    addend = -3600
                timeTuple = time.localtime(t + addend)
        dfn = self.baseFilename + "." + time.strftime(self.suffix, timeTuple)
        if not os.path.exists(dfn) and os.path.exists(self.baseFilename):
            # new file lock

            with lock:
                # lock_file_handler = open(self.baseFilename)
                # fcntl.flock(lock_file_handler, fcntl.LOCK_EX)
                if not os.path.exists(dfn) and os.path.exists(self.baseFilename):
                    os.rename(self.baseFilename, dfn)
                # del file lock
                # fcntl.flock(lock_file_handler, fcntl.LOCK_UN)
                # lock_file_handler.close()
        if self.backupCount > 0:
            for s in self.getFilesToDelete():
                os.remove(s)
        self.mode = "a"
        self.stream = self._open()
        newRolloverAt = self.computeRollover(currentTime)
        while newRolloverAt <= currentTime:
            newRolloverAt = newRolloverAt + self.interval
        if (self.when == 'MIDNIGHT' or self.when.startswith('W')) and not self.utc:
            dstAtRollover = time.localtime(newRolloverAt)[-1]
            if dstNow != dstAtRollover:
                if not dstNow:
                    addend = -3600
                else:
                    addend = 3600
                newRolloverAt += addend
        self.rolloverAt = newRolloverAt


class Logger(object):
    """
    logger class
    """
    log_instance = None
    log_mutex = threading.Lock()

    def __init__(self):
        """
        init function
        """
        # new logging
        self._logger = logging.getLogger()
        self._logger.setLevel(logging.DEBUG)
        # mkdir logs
        if not os.path.exists("./logs"):
            os.mkdir("./logs")

        log_name = './logs/goswr_api_app.log'
        fh = MutilRotatingFileHandler(log_name, when='D', interval=1, backupCount=40)
        fh.setLevel(logging.INFO)

        # new handler for console log
        ch = logging.StreamHandler()
        ch.setLevel(logging.INFO)

        # new format
        fmt = '%(asctime)s - %(levelname)s: %(message)s'
        formatter = logging.Formatter(fmt)
        fh.setFormatter(formatter)
        ch.setFormatter(formatter)

        # add haddler
        self._logger.addHandler(fh)
        self._logger.addHandler(ch)

    @staticmethod
    def format(caller, message):
        """
        log format, add line num
        """
        name = os.path.basename(caller[-2][0])
        line = caller[-2][1]
        return "  * [%s:%s] %s" % (name, line, message)

    @staticmethod
    def get_instance():
        """
        get log instance
        """
        if (Logger.log_instance is None):
            Logger.log_mutex.acquire()
            if (Logger.log_instance is None):
                Logger.log_instance = Logger()
            Logger.log_mutex.release()
        return Logger.log_instance._logger

    @staticmethod
    def writelog(level, message):
        """
        write log
        """
        func = getattr(Logger.get_instance(), level)
        func(Logger.format(traceback.extract_stack(), message))
